﻿using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Daq331m
{
    /*
     * DAQ331M采样率
     */
    internal enum DaqVoltage
    {
        Voltage2V5 = 5, // 2.5V电压量程
        Voltage5V = 6, // 5V电压量程
        Voltage10V = 7, // 10V电压量程
        Voltage15V = 8 // 15V电压量程
    }

    internal enum DaqAdcChannel
    {
        Ain1 = 0b00000001, // ADC通道1
        Ain2 = 0b00000001 << 1, // ADC通道2
        Ain3 = 0b00000001 << 2, // ADC通道3
        Ain4 = 0b00000001 << 3, // ADC通道4
        Ain5 = 0b00000001 << 4, // ADC通道5
        Ain6 = 0b00000001 << 5, // ADC通道6
        Ain7 = 0b00000001 << 6, // ADC通道7
        Ain8 = 0b00000001 << 7, // ADC通道8
        AinAll = 0b11111111 // ADC通道8
    }

    internal enum DaqSampleRate
    {
        SampleRate80 = 80, // 80采样率
        SampleRate100 = 100, // 100采样率
        SampleRate500 = 500, // 500采样率
        SampleRate1K = 1000, // 1K采样率
        SampleRate5K = 5000, // 5K采样率
        SampleRate10K = 10000, // 10K采样率
        SampleRate50K = 50000, // 50K采样率
        SampleRate100K = 100000 // 100K采样率
    }

    internal enum DaqPwmChannel
    {
        Pwm1 = 1,
        Pwm2 = 2,
    }

    internal enum DaqDacChannel
    {
        Dac1 = 1,
        Dac2 = 2,
    }

    internal enum DaqDacMode
    {
        DirectCurrent = 0,
        Wave = 1,
    }

    internal class Daq331M
    {
        private const string DaqLibName = "libdaq-2.0.0.dll";
        private IntPtr _daq331M;

        public Daq331M()
        {
            // 设置相对路径
            var baseDir = AppDomain.CurrentDomain.BaseDirectory;
            var dllDir = Environment.Is64BitProcess
                ? @"..\..\..\..\..\..\lib\Windows\libdaq\lib\x64\msvc2019"
                : @"..\..\..\..\..\..\lib\Windows\libdaq\lib\x86\msvc2019";

            // 检查源目录是否存在
            if (!Directory.Exists(dllDir))
            {
                Console.WriteLine(@"Source directory does not exist.");
                return;
            }

            // 复制动态库到编译目录
            var sourceDllPath = Path.Combine(dllDir, DaqLibName);
            var destDllPath = Path.Combine(baseDir, DaqLibName);

            try
            {
                File.Copy(sourceDllPath, destDllPath, true);
                Console.WriteLine($@"Copied {dllDir} to {baseDir}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($@"Failed to copy DLL: {ex.Message}");
            }
        }

        public void CreateDevice()
        {
            _daq331M = DAQ331M_New();
        }

        public void DeleteDevice()
        {
            if (_daq331M == IntPtr.Zero) return;

            DAQ331M_Delete(_daq331M);
            _daq331M = IntPtr.Zero;
        }

        public bool InitializeDevice()
        {
            return _daq331M != IntPtr.Zero && DAQ331M_InitializeDevice(_daq331M);
        }

        public bool ConnectedDevice()
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConnectedDevice(_daq331M);
        }

        public bool UseSerialBackend(string uartName, uint baudRate)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var uartNamePtr = Marshal.StringToHGlobalAnsi(uartName);

            var result = DAQ331M_UseSerialBackend(_daq331M, uartNamePtr, baudRate);

            Marshal.FreeHGlobal(uartNamePtr);

            return result;
        }

        public bool UseTcpClientBackend(string ipAddress, int port)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var ipAddressPtr = Marshal.StringToHGlobalAnsi(ipAddress);

            var result = DAQ331M_UseTCPClientBackend(_daq331M, ipAddressPtr, port);

            Marshal.FreeHGlobal(ipAddressPtr);

            return result;
        }

        public bool UseModbusRtuBackend(string uartName, int baudRate, int address)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var uartNamePtr = Marshal.StringToHGlobalAnsi(uartName);

            var result = DAQ331M_UseModbusRTUBackend(_daq331M, uartNamePtr, baudRate, address);

            Marshal.FreeHGlobal(uartNamePtr);

            return result;
        }

        public bool ConfigureAdcParameters(uint sampleRate, uint voltage)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigureADCParameters(_daq331M, sampleRate, voltage);
        }

        public bool ConfigAdcChannel(byte channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigADCChannel(_daq331M, channel);
        }

        public bool StartCollection()
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StartCollection(_daq331M);
        }

        public bool StopCollection()
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StopCollection(_daq331M);
        }

        public unsafe bool TryReadAdcData(uint channel, double[] data, uint readSize, uint timeout = 250)
        {
            if (_daq331M == IntPtr.Zero) return false;

            fixed (double* receiveDataPtr = &data[0])
            {
                var dataPtr = (IntPtr)receiveDataPtr;

                return DAQ331M_TryReadADCData(_daq331M, channel, dataPtr, readSize, timeout);
            }
        }

        public byte GetAdcEnableChannelSize()
        {
            return _daq331M == IntPtr.Zero ? (byte)0 : DAQ331M_GetADCEnableChannelSize(_daq331M);
        }

        public int GetCurrentSampleRate()
        {
            return _daq331M == IntPtr.Zero ? 0 : DAQ331M_GetCurrentSampleRate(_daq331M);
        }

        public byte GetAdcLegalChannelSize()
        {
            return _daq331M == IntPtr.Zero ? (byte)0 : DAQ331M_GetADCLegalChannelSize(_daq331M);
        }

        public bool AdcDataIsReady(uint dataNum)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ADCDataIsReady(_daq331M, dataNum);
        }

        public bool ConfigPwm(uint channel, uint frequency, uint dutyCycle)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigPWM(_daq331M, channel, frequency, dutyCycle);
        }

        public bool StartPwm(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StartPWM(_daq331M, channel);
        }

        public bool StopPwm(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StopPWM(_daq331M, channel);
        }

        public bool ConfigGpo(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigGPO(_daq331M, channel);
        }

        public byte[] ReadGpi()
        {
            if (_daq331M == IntPtr.Zero) return new byte[54];

            var data = DAQ331M_ReadGPI(_daq331M);
            const int length = 54;
            var result = new byte[length];
            Marshal.Copy(data, result, 0, length);
            return result;
        }

        public bool ConfigGpi(uint gpiMode)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigGPI(_daq331M, gpiMode);
        }

        public bool ClearGpiCount(uint gpiChannel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ClearGPICount(_daq331M, gpiChannel);
        }

        public bool ConfigCounter(uint channel, uint mode, uint type)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ConfigCounter(_daq331M, channel, mode, type);
        }

        public bool StartCounter(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StartCounter(_daq331M, channel);
        }

        public bool StopCounter(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_StopCounter(_daq331M, channel);
        }

        public bool ClearCounter(uint channel)
        {
            return _daq331M != IntPtr.Zero && DAQ331M_ClearCounter(_daq331M, channel);
        }

        public uint[] ReadCounter()
        {
            if (_daq331M == IntPtr.Zero) return new uint[6];

            var data = DAQ331M_ReadCounter(_daq331M);
            const int length = 6;
            var intResult = new int[length];
            Marshal.Copy(data, intResult, 0, length);
            var result = new uint[length];
            for (var i = 0; i < length; i++)
            {
                result[i] = (uint)intResult[i];
            }

            return result;
        }

        public bool ConfigDACMode(uint channel, uint mode)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var result = DAQ331M_ConfigDACMode(_daq331M, channel, mode);
            return result;
        }

        public bool ConfigDACDirectCurrentData(uint channel, double data)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var result = DAQ331M_ConfigDACDirectCurrentData(_daq331M, channel, data);
            return result;
        }

        public unsafe bool ConfigDACWaveData(uint channel, uint frequency, double[] data)
        {
            if (_daq331M == IntPtr.Zero) return false;

            fixed (double* dataPtr = &data[0])
            {
                var tempPtr = (IntPtr)dataPtr;
                return DAQ331M_ConfigDACWaveData(_daq331M, channel, frequency, tempPtr);
            }
        }

        public bool StartDAC(uint channel)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var result = DAQ331M_StartDAC(_daq331M, channel);
            return result;
        }

        public bool StopDAC(uint channel)
        {
            if (_daq331M == IntPtr.Zero) return false;

            var result = DAQ331M_StopDAC(_daq331M, channel);
            return result;
        }

        public unsafe bool SetMacAddress(byte[] data)
        {
            if (_daq331M == IntPtr.Zero || data.Length != 6) return false;

            fixed (byte* dataPtr = &data[0])
            {
                var tempPtr = (IntPtr)dataPtr;
                return DAQ331M_SetMacAddress(_daq331M, tempPtr);
            }
        }

        public unsafe bool SetNetConfig(byte[] data)
        {
            if (_daq331M == IntPtr.Zero || data.Length != 12)
                return false;

            fixed (byte* dataPtr = &data[0])
            {
                var tempPtr = (IntPtr)dataPtr;
                return DAQ331M_SetNetConfig(_daq331M, tempPtr);
            }
        }

        public unsafe bool SetServerPort(byte[] data)
        {
            if (_daq331M == IntPtr.Zero || data.Length != 2)
                return false;

            fixed (byte* dataPtr = &data[0])
            {
                var tempPtr = (IntPtr)dataPtr;
                return DAQ331M_SetServerPort(_daq331M, tempPtr);
            }
        }

        // 创建DAQ331M
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr DAQ331M_New();

        // 删除DAQ331M对象
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_Delete(IntPtr pointer);

        // 初始化DAQ331M
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_InitializeDevice(IntPtr pointer);

        // 连接DAQ331M
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConnectedDevice(IntPtr pointer);

        // 串口-RS485通信
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_UseSerialBackend(IntPtr pointer, IntPtr uartName, uint baudRate);

        // TCP客户端通信
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_UseTCPClientBackend(IntPtr pointer, IntPtr ipAddress, int port);

        // ModbusRTU协议通信
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_UseModbusRTUBackend(IntPtr pointer, IntPtr uartName, int baudRate,
            int address);

        // 配置设备ADC参数
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigureADCParameters(IntPtr pointer, uint voltage, uint samplingRate);

        // 配置ADC通道
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigADCChannel(IntPtr pointer, byte channel);

        // 开始采集
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StartCollection(IntPtr pointer);

        // 停止采集
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StopCollection(IntPtr pointer);

        // 读取数据
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_TryReadADCData(IntPtr pointer, uint channel, IntPtr data, uint readSize,
            uint timeout);

        // 获取DAQ331M当前使能的通道数量
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern byte DAQ331M_GetADCEnableChannelSize(IntPtr pointer);

        // 获取DAQ331M当前采样率
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern int DAQ331M_GetCurrentSampleRate(IntPtr pointer);

        // 获取DAQ331M当前采样率
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern byte DAQ331M_GetADCLegalChannelSize(IntPtr pointer);

        // 判断当前所有通道缓冲区的数据量是否超过指定数值
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ADCDataIsReady(IntPtr pointer, uint dataNum);

        // 配置PWM
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigPWM(IntPtr pointer, uint channel, uint frequency, uint dutyCycle);

        // 开启PWM
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StartPWM(IntPtr pointer, uint channel);

        // 关闭PWM
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StopPWM(IntPtr pointer, uint channel);

        // 配置DO
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigGPO(IntPtr pointer, uint channel);

        // 读DI数据
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr DAQ331M_ReadGPI(IntPtr pointer);

        // 配置DI
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigGPI(IntPtr pointer, uint gpiMode);

        // 清除DI计数
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ClearGPICount(IntPtr pointer, uint gpiChannel);

        // 配置计数器
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigCounter(IntPtr pointer, uint channel, uint mode, uint type);

        // 开启计数器
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StartCounter(IntPtr pointer, uint channel);

        // 停止计数器
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StopCounter(IntPtr pointer, uint channel);

        // 计数器清零
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ClearCounter(IntPtr pointer, uint channel);

        // 读取计数器
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr DAQ331M_ReadCounter(IntPtr pointer);

        // DAC 模式配置
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigDACMode(IntPtr pointer, uint channel, uint mode);

        // DAC 直流数据配置
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigDACDirectCurrentData(IntPtr pointer, uint channel, double data);

        // DAC 波形数据配置
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_ConfigDACWaveData(IntPtr pointer, uint channel, uint frequency, IntPtr data);

        // 开启 DAC 输出
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StartDAC(IntPtr pointer, uint channel);

        // 停止 DAC 输出
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_StopDAC(IntPtr pointer, uint channel);

        // 配置MAC地址
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_SetMacAddress(IntPtr pointer, IntPtr data);

        // 配置网络信息
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_SetNetConfig(IntPtr pointer, IntPtr data);

        // 配置端口信息
        [DllImport(DaqLibName, CallingConvention = CallingConvention.Cdecl)]
        private static extern bool DAQ331M_SetServerPort(IntPtr pointer, IntPtr data);
    }
}